package com.bigfans.searchservice.service.impl;

import com.bigfans.framework.es.ElasticTemplate;
import com.bigfans.framework.es.request.SearchCriteria;
import com.bigfans.framework.es.request.SearchResult;
import com.bigfans.framework.model.FTSPageBean;
import com.bigfans.framework.utils.CollectionUtils;
import com.bigfans.framework.utils.StringHelper;
import com.bigfans.searchservice.document.convertor.ProductDocumentConverter;
import com.bigfans.searchservice.model.Product;
import com.bigfans.searchservice.model.ProductSearchRequest;
import com.bigfans.searchservice.schema.mapping.ProductMapping;
import com.bigfans.searchservice.service.ProductSearchService;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 
 * @Description:搜索服务类
 * @author lichong
 * 2015年4月22日下午9:08:57
 *
 */
@Service(ProductSearchServiceImpl.BEAN_NAME)
public class ProductSearchServiceImpl implements ProductSearchService {
	
	public static final String BEAN_NAME = "productSearchService";
	
	@Autowired
	private ElasticTemplate elasticTemplate;
	
	public FTSPageBean<Product> searchProduct(ProductSearchRequest param , int from , int size) throws Exception {
		// 1. 查询条件
		BoolQueryBuilder finalQuery = QueryBuilders.boolQuery();
		// 1.1 关键字查询条件
		if(StringHelper.isNotEmpty(param.getKeyword())){
			MatchQueryBuilder keywdQuery = QueryBuilders.matchQuery(ProductMapping.FIELD_NAME, param.getKeyword());
			keywdQuery.boost(4);
			finalQuery.should(keywdQuery);
		}
		// 1.2 标签查询条件
		if(StringHelper.isNotEmpty(param.getTagId())){
			TermQueryBuilder termQuery = QueryBuilders.termQuery(ProductMapping.FIELD_TAGS + "."+ ProductMapping.FIELD_TAG_ID, param.getTagId());
			NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(ProductMapping.FIELD_TAGS, termQuery,ScoreMode.None);
			nestedQuery.boost(1);
			finalQuery.should(nestedQuery);
		}
		
		// 2. 过滤条件
		// 2.1 类别过滤条件
		if(StringHelper.isNotEmpty(param.getCategoryId())){
			QueryBuilder catFilter = QueryBuilders.termQuery(ProductMapping.FIELD_CATEGORY_ID, param.getCategoryId());
			finalQuery.must(catFilter);
		}
		// 2.2 品牌过滤条件
		if(StringHelper.isNotEmpty(param.getBrandId())){
			QueryBuilder brandFilter = QueryBuilders.termQuery(ProductMapping.FIELD_BRAND_ID, param.getBrandId());
			finalQuery.must(brandFilter);
		}
		// 2.3 价格过滤条件
		if(StringHelper.isNotEmpty(param.getMinPrice()) && StringHelper.isNotEmpty(param.getMaxPrice())){
			RangeQueryBuilder priceFilter = QueryBuilders.rangeQuery(ProductMapping.FIELD_PRICE).from(param.getMinPrice()).to(param.getMaxPrice());
			finalQuery.must(priceFilter);
		}
		// 2.4 其他属性过滤条件
		Map<String, String> attrsMap = param.getAttrs();
		if(CollectionUtils.isNotEmpty(attrsMap)){
			for(Map.Entry<String, String> entry : attrsMap.entrySet()){
				QueryBuilder attrFilter = QueryBuilders.termQuery(ProductMapping.FIELD_ATTRIBUTES + "."+ ProductMapping.FIELD_ATTRIBUTE_VALID, entry.getValue());
				NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(ProductMapping.FIELD_ATTRIBUTES, attrFilter,ScoreMode.None);
				finalQuery.must(nestedQuery);
			}
		}
		
		// 3. 聚合条件
		List<AggregationBuilder> aggregations = new ArrayList<>();
		//	3.1 按照类别聚合
		AggregationBuilder catAggrBuilder = AggregationBuilders.terms(ProductMapping.FIELD_CATEGORY).field(ProductMapping.FIELD_CATEGORY_ID);
		aggregations.add(catAggrBuilder);
		//	3.2 按照品牌聚合
		AggregationBuilder brandAggrBuilder = AggregationBuilders.terms(ProductMapping.FIELD_BRAND).field(ProductMapping.FIELD_BRAND_ID);
		aggregations.add(brandAggrBuilder);
		// 	3.3 按照属性聚合
		String aggrName = ProductMapping.FIELD_ATTRIBUTES + "." +ProductMapping.FIELD_ATTRIBUTE_VALID;
		NestedAggregationBuilder aggregationBuilder = AggregationBuilders.nested(ProductMapping.FIELD_ATTRIBUTES , ProductMapping.FIELD_ATTRIBUTES);
		aggregationBuilder.subAggregation(AggregationBuilders.terms(ProductMapping.FIELD_ATTRIBUTES).field(aggrName));
		aggregations.add(aggregationBuilder);
		
		// 4. 排序条件
		// 	4.1 默认排序
		//	4.2 自定义排序
		Map<String, String> sortMap = param.getSorts();
		List<FieldSortBuilder> sortBuilders = new ArrayList<FieldSortBuilder>();
		if(CollectionUtils.isNotEmpty(sortMap)){
			for(Map.Entry<String, String> entry : sortMap.entrySet()){
				if(entry.getValue().equals("asc")){
					FieldSortBuilder sortBuilder = SortBuilders.fieldSort(entry.getKey()).order(SortOrder.ASC);
					sortBuilders.add(sortBuilder);
				} else if (entry.getValue().equals("desc")){
					FieldSortBuilder sortBuilder = SortBuilders.fieldSort(entry.getKey()).order(SortOrder.DESC);
					sortBuilders.add(sortBuilder);
				}
			}
		}
		
		SearchCriteria searchCriteria = new SearchCriteria(finalQuery , null , sortBuilders , aggregations);
		searchCriteria.setIndex(ProductMapping.INDEX);
		searchCriteria.setType(ProductMapping.TYPE);
		searchCriteria.setFrom(from);
		searchCriteria.setSize(size);
		searchCriteria.setMinScore(0.1f);
		
		SearchResult<Product> result = elasticTemplate.search(searchCriteria, new ProductDocumentConverter());
		List<Product> productList = result.getData();
		FTSPageBean<Product> pageBean = new FTSPageBean<>(productList, result.getTotHitis());
		pageBean.setAggregationList(result.getAggregationList());
		
		return pageBean;
	}

}
